#include <game/game.h>
#include <game/localplayer.h>
#include <game/networkplayer.h>

#include <physics/pstar.h>
#include <physics/pplanet.h>

#include <QFile>
#include <QDomDocument>

//#include <QElapsedTimer>
//#include <QDebug>

Game::Game(KeyManager *manager, QObject *parent) :
    QObject(parent)
{
    myWorld = 0;
    myKeyManager = manager;
    myTimer = 0;
    refresh();
}

void Game::timerEvent(QTimerEvent *) {
    myWorld->tick(2);

    //qDebug() << "The physic operation took" << timer.elapsed() << "milliseconds";

    int countPlayersAlive = 0;
    foreach (Player *pl, myPlayers) {
        if (pl->isAlive()) {
            countPlayersAlive++;
        }
    }
    if (countPlayersAlive <= 1) {
        myState = "game over";
        killTimer(myTimer);
        myTimer = 0;
    }

    //QElapsedTimer timer;
    //timer.start();

    emit updated();

    //(*myFunc)();
    //qDebug() << "The emit operation took" << timer.elapsed() << "milliseconds";
}

void Game::pause() {
    if(myTimer == 0) {
        return;
    }
    killTimer(myTimer);
    myTimer = 0;
    myState = "paused";
}

void Game::play() {
    if (myTimer == 0) {
        myTimer = startTimer(30);
        myState = "playing";
    }
}

void Game::refresh() {
    qDebug("refreshing game");
    if (myTimer) {
        killTimer(myTimer);
        myTimer = 0;
    }
    if (myWorld != 0) {
        myPlayers.clear();
        //delete myWorld;
        myWorld = 0;
    }
    if (myStartState == "") {
        QFile in(":/config.xml");
        if (!in.open(QIODevice::ReadOnly)) {
            return;
        }
        myStartState = in.readAll();
        in.close();
    }
    QDomDocument doc;
    doc.setContent(myStartState);

    QDomNode node = doc.firstChild();

    if (!node.isNull() && node.toElement().tagName() == "root") {
        deserializeMe(node.firstChild());
    }
}

PWorld *Game::getWorld() const {
    return myWorld;
}

QVector<Player *> Game::getPlayers() const {
    return myPlayers;
}

QString Game::getState() const {
    return myState;
}

void Game::serialize(QDomDocument *doc, QDomElement *e) const {
    QDomElement elem = doc->createElement("Game");

    QDomElement state = doc->createElement("State");
    QDomText state_v = doc->createTextNode(myState);
    state.appendChild(state_v);
    elem.appendChild(state);

    QDomElement players = doc->createElement("Players");
    foreach (Player *pl, myPlayers) {
        QDomElement elem = doc->createElement("Player");

        pl->serialize(doc, &elem);
        players.appendChild(elem);
    }
    elem.appendChild(players);

    myWorld->serialize(doc, &elem);

    e->appendChild(elem);
}

void Game::deserializeMe(QDomNode e) {
    if (myTimer) {
        killTimer(myTimer);
        myTimer = 0;
    }
    if (myWorld != 0) {
        myPlayers.clear();
        myWorld->deleteLater();
    }
    QString state = "";
    QVector<Player *> players;
    QDomNode n = e.firstChild();
    QDomNode playersNode;
    while (!n.isNull()) {
        QString name = n.toElement().tagName();
        if (name == "State") {
            state = n.toElement().firstChild().toText().data();
        } else if (name == "Players") {
            playersNode = n;
            //qDebug("players");
        } else if (name == "World") {
            myWorld = PWorld::deserialize(n, this);
        }
        n = n.nextSibling();
    }
    QDomNode player = playersNode.firstChild();
    while (!player.isNull()) {
        //qDebug(player.toElement().attribute("type").toStdString().c_str());
        if (player.toElement().attribute("type") == "LocalPlayer") {
            players.append(LocalPlayer::deserialize(player, myWorld, myKeyManager));
        } else if (player.toElement().attribute("type") == "NetworkPlayer") {
            players.append(NetworkPlayer::deserialize(player, myWorld));
        }
        player = player.nextSibling();
    }
    myState = state;
    myPlayers = players;
}

void Game::deserializeCommand(QDomNode e) {
    QDomNode n = e.firstChild();
    while (!n.isNull()) {
        QString name = n.toElement().tagName();
        if (name == "ChangeState") {
            myState = n.toElement().firstChild().toText().data();
        } else if (name == "Player") {
            QString command = n.toElement().firstChild().toText().data();
            NetworkPlayer *npl = 0;
            foreach (Player *pl, myPlayers) {
                if (pl->getType() == "NetworkPlayer") {
                    npl = (NetworkPlayer *)pl;
                }
            }
            if (command == "Accelerate") {
                npl->pressAccelerate();
            } else if (command == "Fire") {
                npl->pressFire();
            } else if (command == "Left") {
                npl->pressLeft();
            } else if (command == "Right") {
                npl->pressRight();
            } else if (command == "NAccelerate") {
                npl->releaseAccelerate();
            } else if (command == "NFire") {
                npl->releaseFire();
            } else if (command == "NLeft") {
                npl->releaseLeft();
            } else if (command == "NRight") {
                npl->releaseRight();
            }
        }
        n = n.nextSibling();
    }
    if(myState == "playing") {
        Game::play();
    } else if(myState == "paused") {
        Game::pause();
    }
}
